//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package project_issue_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/issue_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/api-server/utils"
	"atomgit.com/openlinksaas/proto-gen-go.git/notices/notices_issue"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_issue_api"
	"github.com/google/uuid"
	"go.mongodb.org/mongo-driver/mongo"
)

// 增加子工单
func (apiImpl *ProjectIssueApiImpl) CreateSubIssue(ctx context.Context, req *project_issue_api.CreateSubIssueRequest) (*project_issue_api.CreateSubIssueResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.CreateSubIssueResponse{
			Code:   project_issue_api.CreateSubIssueResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.CreateSubIssueResponse{
			Code:   project_issue_api.CreateSubIssueResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.CreateSubIssueResponse{
			Code:   project_issue_api.CreateSubIssueResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_issue_api.CreateSubIssueResponse{
			Code:   project_issue_api.CreateSubIssueResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	issueItem, err := issue_dao.IssueDao.Get(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return &project_issue_api.CreateSubIssueResponse{
			Code:   project_issue_api.CreateSubIssueResponse_CODE_NO_ISSUE,
			ErrMsg: "工单不存在",
		}, nil
	}
	//只有管理员和相关人员可以创建子工单
	if !(sessionItem.UserId == projectItem.OwnerUserId || roleItem.BasicInfo.Admin || sessionItem.UserId == issueItem.CreateUserId ||
		sessionItem.UserId == issueItem.ExecUserId || sessionItem.UserId == issueItem.CheckUserId) {
		return &project_issue_api.CreateSubIssueResponse{
			Code:   project_issue_api.CreateSubIssueResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	subIssueId := uuid.NewString()
	nowTime := time.Now().UnixNano() / 1e6
	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = issue_dao.SubIssueDao.Insert(sessCtx, &issue_dao.SubIssueInfoDbItem{
			SubIssueId: subIssueId,
			ProjectId:  req.ProjectId,
			IssueId:    req.IssueId,
			BasicInfo: issue_dao.BasicSubIssueInfoDbItem{
				Title: req.BasicInfo.Title,
			},
			CreateUserId: sessionItem.UserId,
			CreateTime:   nowTime,
			UpdateTime:   nowTime,
			Done:         false,
		})
		if err != nil {
			return nil, err
		}
		return &project_issue_api.CreateSubIssueResponse{
			Code:       project_issue_api.CreateSubIssueResponse_CODE_OK,
			SubIssueId: subIssueId,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addCreateSubIssueEvent(sessionItem, req, projectItem, issueItem)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateSubIssueNotice{
		ProjectId: req.ProjectId,
		IssueId:   req.IssueId,
	})
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateIssueNotice{
		ProjectId: req.ProjectId,
		IssueId:   req.IssueId,
	})
	return ret.(*project_issue_api.CreateSubIssueResponse), nil
}

// 更新子工单
func (apiImpl *ProjectIssueApiImpl) UpdateSubIssue(ctx context.Context, req *project_issue_api.UpdateSubIssueRequest) (*project_issue_api.UpdateSubIssueResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.UpdateSubIssueResponse{
			Code:   project_issue_api.UpdateSubIssueResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.UpdateSubIssueResponse{
			Code:   project_issue_api.UpdateSubIssueResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.UpdateSubIssueResponse{
			Code:   project_issue_api.UpdateSubIssueResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_issue_api.UpdateSubIssueResponse{
			Code:   project_issue_api.UpdateSubIssueResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	issueItem, err := issue_dao.IssueDao.Get(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return &project_issue_api.UpdateSubIssueResponse{
			Code:   project_issue_api.UpdateSubIssueResponse_CODE_NO_ISSUE,
			ErrMsg: "工单不存在",
		}, nil
	}
	//只有管理员和相关人员可以修改子工单
	if !(sessionItem.UserId == projectItem.OwnerUserId || roleItem.BasicInfo.Admin || sessionItem.UserId == issueItem.CreateUserId ||
		sessionItem.UserId == issueItem.ExecUserId || sessionItem.UserId == issueItem.CheckUserId) {
		return &project_issue_api.UpdateSubIssueResponse{
			Code:   project_issue_api.UpdateSubIssueResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	subIssueItem, err := issue_dao.SubIssueDao.Get(ctx, req.ProjectId, req.IssueId, req.SubIssueId)
	if err != nil {
		return &project_issue_api.UpdateSubIssueResponse{
			Code:   project_issue_api.UpdateSubIssueResponse_CODE_NO_SUB_ISSUE,
			ErrMsg: "子工单不存在",
		}, nil
	}
	if subIssueItem.BasicInfo.Title == req.BasicInfo.Title {
		return &project_issue_api.UpdateSubIssueResponse{
			Code: project_issue_api.UpdateSubIssueResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = issue_dao.SubIssueDao.UpdateBasicInfo(sessCtx, req.ProjectId, req.IssueId, req.SubIssueId, &issue_dao.BasicSubIssueInfoDbItem{
			Title: req.BasicInfo.Title,
		})
		if err != nil {
			return nil, err
		}
		return &project_issue_api.UpdateSubIssueResponse{
			Code: project_issue_api.UpdateSubIssueResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addUpdateSubIssueEvent(sessionItem, req, projectItem, issueItem, subIssueItem)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateSubIssueNotice{
		ProjectId: req.ProjectId,
		IssueId:   req.IssueId,
	})
	go api_common.SendNoticeToProjectScope(context.Background(), projectItem.ProjectId, &notices_issue.UpdateIssueNotice{
		ProjectId: projectItem.ProjectId,
		IssueId:   issueItem.IssueId,
	})
	return ret.(*project_issue_api.UpdateSubIssueResponse), nil
}

// 更新子工单状态
func (apiImpl *ProjectIssueApiImpl) UpdateSubIssueState(ctx context.Context, req *project_issue_api.UpdateSubIssueStateRequest) (*project_issue_api.UpdateSubIssueStateResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.UpdateSubIssueStateResponse{
			Code:   project_issue_api.UpdateSubIssueStateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.UpdateSubIssueStateResponse{
			Code:   project_issue_api.UpdateSubIssueStateResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.UpdateSubIssueStateResponse{
			Code:   project_issue_api.UpdateSubIssueStateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_issue_api.UpdateSubIssueStateResponse{
			Code:   project_issue_api.UpdateSubIssueStateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	issueItem, err := issue_dao.IssueDao.Get(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return &project_issue_api.UpdateSubIssueStateResponse{
			Code:   project_issue_api.UpdateSubIssueStateResponse_CODE_NO_ISSUE,
			ErrMsg: "工单不存在",
		}, nil
	}
	//只有管理员和相关人员可以修改子工单
	if !(sessionItem.UserId == projectItem.OwnerUserId || roleItem.BasicInfo.Admin || sessionItem.UserId == issueItem.CreateUserId ||
		sessionItem.UserId == issueItem.ExecUserId || sessionItem.UserId == issueItem.CheckUserId) {
		return &project_issue_api.UpdateSubIssueStateResponse{
			Code:   project_issue_api.UpdateSubIssueStateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	subIssueItem, err := issue_dao.SubIssueDao.Get(ctx, req.ProjectId, req.IssueId, req.SubIssueId)
	if err != nil {
		return &project_issue_api.UpdateSubIssueStateResponse{
			Code:   project_issue_api.UpdateSubIssueStateResponse_CODE_NO_SUB_ISSUE,
			ErrMsg: "子工单不存在",
		}, nil
	}
	if subIssueItem.Done == req.Done {
		return &project_issue_api.UpdateSubIssueStateResponse{
			Code: project_issue_api.UpdateSubIssueStateResponse_CODE_OK,
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = issue_dao.SubIssueDao.UpdateDoneFlag(sessCtx, req.ProjectId, req.IssueId, req.SubIssueId, req.Done)
		if err != nil {
			return nil, err
		}
		return &project_issue_api.UpdateSubIssueStateResponse{
			Code: project_issue_api.UpdateSubIssueStateResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addUpdateSubIssueStateEvent(sessionItem, req, projectItem, issueItem, subIssueItem)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateSubIssueNotice{
		ProjectId: req.ProjectId,
		IssueId:   req.IssueId,
	})
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateIssueNotice{
		ProjectId: req.ProjectId,
		IssueId:   req.IssueId,
	})
	return ret.(*project_issue_api.UpdateSubIssueStateResponse), nil
}

// 列出子工单
func (apiImpl *ProjectIssueApiImpl) ListSubIssue(ctx context.Context, req *project_issue_api.ListSubIssueRequest) (*project_issue_api.ListSubIssueResponse, error) {
	emptyList := []*project_issue_api.SubIssueInfo{}
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.ListSubIssueResponse{
			Code:         project_issue_api.ListSubIssueResponse_CODE_WRONG_SESSION,
			ErrMsg:       "会话不存在",
			SubIssueList: emptyList,
		}, nil
	}
	_, _, _, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.ListSubIssueResponse{
			Code:         project_issue_api.ListSubIssueResponse_CODE_NO_PROJECT,
			ErrMsg:       "项目不存在",
			SubIssueList: emptyList,
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.ListSubIssueResponse{
			Code:         project_issue_api.ListSubIssueResponse_CODE_NO_PERMISSION,
			ErrMsg:       "没有权限",
			SubIssueList: emptyList,
		}, nil
	} else if err != nil {
		return nil, err
	}

	exist, err := issue_dao.IssueDao.Exist(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return nil, err
	}
	if !exist {
		return &project_issue_api.ListSubIssueResponse{
			Code:         project_issue_api.ListSubIssueResponse_CODE_NO_ISSUE,
			ErrMsg:       "工单不存在",
			SubIssueList: emptyList,
		}, nil
	}

	subIssueItemList, err := issue_dao.SubIssueDao.ListByIssue(ctx, req.ProjectId, []string{req.IssueId})
	if err != nil {
		return nil, err
	}
	//补充用户信息
	userIdList := []string{}
	for _, subIssueItem := range subIssueItemList {
		userIdList = append(userIdList, subIssueItem.CreateUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}

	subIssueList := []*project_issue_api.SubIssueInfo{}
	for _, subIssueItem := range subIssueItemList {
		subIssue := subIssueItem.ToSubIssueInfo()
		memberInfo, ok := userItemMap[subIssueItem.CreateUserId]
		if ok {
			subIssue.CreateDisplayName = memberInfo.BasicInfo.DisplayName
		}
		subIssueList = append(subIssueList, subIssue)
	}

	return &project_issue_api.ListSubIssueResponse{
		Code:         project_issue_api.ListSubIssueResponse_CODE_OK,
		SubIssueList: subIssueList,
	}, nil
}

// 删除子工单
func (apiImpl *ProjectIssueApiImpl) RemoveSubIssue(ctx context.Context, req *project_issue_api.RemoveSubIssueRequest) (*project_issue_api.RemoveSubIssueResponse, error) {
	sessionItem, ok := dao.CacheDao.GetSession(ctx, req.SessionId)
	if !ok {
		return &project_issue_api.RemoveSubIssueResponse{
			Code:   project_issue_api.RemoveSubIssueResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	projectItem, _, roleItem, err := utils.GetProjectMemberRole(ctx, req.ProjectId, sessionItem.UserId)
	if err == utils.ErrNoProject {
		return &project_issue_api.RemoveSubIssueResponse{
			Code:   project_issue_api.RemoveSubIssueResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	} else if err == utils.ErrNoRole {
		return &project_issue_api.RemoveSubIssueResponse{
			Code:   project_issue_api.RemoveSubIssueResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	} else if err != nil {
		return nil, err
	}
	if projectItem.Closed {
		return &project_issue_api.RemoveSubIssueResponse{
			Code:   project_issue_api.RemoveSubIssueResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}
	issueItem, err := issue_dao.IssueDao.Get(ctx, req.ProjectId, req.IssueId)
	if err != nil {
		return &project_issue_api.RemoveSubIssueResponse{
			Code:   project_issue_api.RemoveSubIssueResponse_CODE_NO_ISSUE,
			ErrMsg: "工单不存在",
		}, nil
	}
	//只有管理员和相关人员可以删除子工单
	if !(sessionItem.UserId == projectItem.OwnerUserId || roleItem.BasicInfo.Admin || sessionItem.UserId == issueItem.CreateUserId ||
		sessionItem.UserId == issueItem.ExecUserId || sessionItem.UserId == issueItem.CheckUserId) {
		return &project_issue_api.RemoveSubIssueResponse{
			Code:   project_issue_api.RemoveSubIssueResponse_CODE_NO_ISSUE,
			ErrMsg: "工单不存在",
		}, nil
	}

	subIssueItem, err := issue_dao.SubIssueDao.Get(ctx, req.ProjectId, req.IssueId, req.SubIssueId)
	if err != nil {
		return &project_issue_api.RemoveSubIssueResponse{
			Code:   project_issue_api.RemoveSubIssueResponse_CODE_NO_SUB_ISSUE,
			ErrMsg: "子工单不存在",
		}, nil
	}

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		err = issue_dao.SubIssueDao.Remove(sessCtx, req.ProjectId, req.IssueId, req.SubIssueId)
		if err != nil {
			return nil, err
		}
		return &project_issue_api.RemoveSubIssueResponse{
			Code: project_issue_api.RemoveSubIssueResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	//记录事件
	go apiImpl.addRemoveSubIssueEvent(sessionItem, req, projectItem, issueItem, subIssueItem)
	//发送通知
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateSubIssueNotice{
		ProjectId: req.ProjectId,
		IssueId:   req.IssueId,
	})
	go api_common.SendNoticeToProjectScope(context.Background(), req.ProjectId, &notices_issue.UpdateIssueNotice{
		ProjectId: req.ProjectId,
		IssueId:   req.IssueId,
	})
	return ret.(*project_issue_api.RemoveSubIssueResponse), nil
}
